(function($){
var URLPRE = 'http://john.douban.com/group/topic/';
/**
 * Ajax.get的快捷方式
 * @param {Object} url 请求url
 * @param {Object} cb 回调函数
 */
$.ajax.get = function(url, cb){
	$.ajax({
		type     : 'GET',
		url      : url,
		dataType : 'html',
		cache    : false,
		success  : function(r){
			cb(r);
		}
	});
}

/**
 * 分发器类
 */
function Deliver(){
	var _procs = {};
	var _default = null;
	//Register a processor
	this.reg = function(name,fn,asDefault){
		_procs[name] = fn;
		if(asDefault){
			_default = fn;
		}
	};
	//Deliver a processor	
	this.get = function(name){
		return _procs[name] || _default;
	};
	//Call all processors
	this.each = function(){
		var args = arguments;
		jQuery.each(_procs, function(name, fn){
			fn.apply(fn,args);
		})
	};	
}	

/**
 * 数据获取类
 * @param {Object} id 帖子ID
 * @param {Object} cb 数据获取后的回调函数
 * @param {Object} userOptions 用户参数
 */
function Getter(id, cb, userOptions){
	/**
	 * 是否正在运行
	 */
	var running = false;
	
	/**
	 * 定时器
	 */
	var runTimer = null;
	
	/**
	 * 帖子ID
	 */
	var topicId = id;
	
	/**
	 * 数据获取后的回调函数
	 */
	var callback = cb;
	
	/**
	 * 总页数
	 */
	var totalPage = 0;
	
	/**
	 * 当前获取的页码,从1开始
	 */
	var curPage = 1;
	
	/**
	 * 默认参数
	 */
	var options = {
		//帖子url前缀
		urlPre : URLPRE,
		//数据获取周期
		period : 5000
	};
	jQuery.extend(options, userOptions);
	
	/**
	 * 数据处理器数组
	 */
	var processers = new Deliver();
	
	/**
	 * 数据处理函数
	 * 在次函数中会依次调用各个数据处理器,并返回处理后的topic对象
	 * topic结构:
	 * {
	 * //作者数组
	 * author : [
	 * 	  {
	 * 		//用户名
	 * 		name : 'john',
	 *  	//用户头像
	 *  	img  : 'xxx.jpg',
	 *  	//用户链接
	 *  	link : '/pepole/john/'
	 * 	  },...
	 *  ],
	 *  //内容数组
	 *  contents : [
	 *    'xxxx','xxxxx',...
	 *  ],
	 *  //更新时间数组
	 *  updates : [
	 *    '2009-01-12 11:11:11',....
	 *  ]
	 * }
	 * @param {Object} r 获取到的html内容
	 */
	function process(r){
		var topic = {
			authors  : [],
			authorsMap : {},
			contents : [],
			updates  : []
		};
		if (curPage == 1){
			totalPage = _pagesProc(r);
		}
		processers.each(topic, r);
		if (curPage < totalPage){
			curPage++;
			getByPage(curPage);
		}
		running = false;
		return callback(topic);
	}

	/**
	 * 获取帖子页数
	 * @param {Object} r
	 */
	function _pagesProc(r){
		var re = /<a href="\/group\/topic\/(?:\d+)\/\?start=/ig;
		var matches = r.match(re);
		if ( ! matches){
			return 1;
		}
		else{
			return matches.length+1;
		}
	}

	/**
	 * 共同处理器,提取了作者,时间,内容处理器中重复的代码
	 * 先根据pattern获取全局中的匹配内容,
	 * 再根据pattern获取局部匹配内容,
	 * 最后将局部匹配的结果作为参数调用回调函数
	 * @param {Object} r
	 * @param {Object} pattern
	 * @param {Object} mode
	 * @param {Object} cb
	 */
	function _commonProc(r, pattern, mode, cb){
		var reg = new RegExp(pattern, mode + 'ig');
		var re  = new RegExp(pattern, mode + 'i');
		var matches = r.match(reg);
		if ( ! matches){
			return false;
		}
		jQuery.each(matches, function(i, match){
			var matches = match.match(re);
			cb(matches);
		});
	}
	
	/**
	 * 提取作者信息
	 * 其中第一条为楼主信息,余下为回复者信息
	 * @param {Object} topic
	 * @param {Object} r
	 */	
	function _authorProc(topic, r){
		_commonProc(
			r,
			'<a href="(/people/(?:[^"]*?))">([^<]*?)</a>',
			'',
			function(matches){
				topic.authors[topic.authors.length] = {
					name : matches[2],
					link : matches[1]				
				};				
			}
		);
	}
	processers.reg('author',_authorProc);
	
	function _authorDetailProc(topic, r){
		_commonProc(
			r,
			'<a href="([^"]*?)"><img class="pil" src="([^"]*?)" alt="([^"]*?)"/></a>',
			'',
			function(matches){
				//name : matches[3],
				//img  : matches[2],
				//link : matches[1]
				topic.authorsMap['_'+matches[1]+'_'] = {
					img  : matches[2]
				};				
			}
		);		
	}
	processers.reg('authorDetail',_authorDetailProc);
	
	/**
	 * 提取内容信息
	 * 其中第一条为主题贴,余下为回复贴
	 * @param {Object} topic
	 * @param {Object} r
	 */
	function _subjectProc(topic, r){
		_commonProc(
			r,
			'<p class="wrc">((?:.|\\n|\\r)*?)</p>',
			'm',
			function(matches){
				topic.contents[topic.contents.length] = matches[1];
			}
		);
	}
	processers.reg('subject', _subjectProc);
	
	/**
	 * 提取帖子时间信息
	 * 其中第一条为主题发布时间,余下为回复时间
	 * @param {Object} topic
	 * @param {Object} r
	 */
	function _updateProc(topic, r){
		var lzUpdate = /<span class="mn">([^<]*?)<\/span>/i;
		var matches = r.match(lzUpdate);
		if (matches){
			//如果是获取多页结果,则只有第一页有主题发表时间
			topic.updates[0] = matches[1];
		}
		_commonProc(
		r,
		'<h4>(.*)(?:\\r|\\s|\\n)*<a(?:.*)</a>',
		'm',
		function(matches){
			topic.updates[topic.updates.length] = matches[1];
		}
		);
	}
	processers.reg('update', _updateProc);
	
	/**
	 * 根据页码获取帖子
	 * @param {Object} p
	 */
	function getByPage(p){
		curPage = p;
		var url = options.urlPre + topicId + '/';;
		if (curPage > 1){
			url = url + '?start=' + ((curPage - 1) * 100)
		}
		$.ajax.get(url, process);
	}
	
	/**
	 * 执行获取数据操作
	 */	
	function run(){
		if (running){
			return;
		}
		running = true;
		getByPage(1);
	}
	
	/**
	 * 开始获取数据
	 */
	this.start = function(){
		run();
		/*
		runTimer = setInterval(function(){
			run();
		}, options.period)
		*/
	};
	
	/**
	 * 停止获取数据
	 */
	this.stop = function(){
		clearInterval(runTimer);
	};
	
	this.getTotalPage = function(){
		return totalPage;
	}
	
	this.process = function(r){
		process(r);
	}
}

/**
 * 数据更新器
 * 根据最近帖子更新时间,将最新发布的帖子更新到页面相应位置
 * @param {Object} userOptions 用户参数
 */
function Updater(userOptions){
	/**
	 * 最近更新的帖子时间
	 */
	var lastUpdate = 0;
	
	/**
	 * 执行更新操作
	 * @param {Object} topic 数据获取器返回的帖子对象
	 */
	this.update = function(topic){
		var html = [];
		jQuery.each(topic.updates, function(i, ts){
			//将'2009-01-12 11:11:11'的格式换为'2009/01/12 11:11:11'格式
			ts = ts.replace(/\-/g, '/');
			//将时间串转为时间戳
			var d = new Date(ts);
			var time = d.getTime();
			//将发布时间大于'最近更新的帖子时间'的帖子内容组织成html
			if (time > lastUpdate){
				lastUpdate  = time;
				var author  = topic.authors[i];
				var authorDetail = topic.authorsMap['_'+author.link+'_'];
				var authorImg = null;
				if (authorDetail && authorDetail.img){
					authorImg = authorDetail.img
				}
				else{
					authorImg = "http://otho.douban.com/icon/g15647-1.jpg";
				}
				var content = topic.contents[i];
				var update  = topic.updates[i];
				html.push([
					'<li class="mbtl">',
						'<a href="',author.link,'">',
							'<img src="',authorImg,'" alt="',author.name,'"/>',
						'</a>',
					'</li>',
		        	'<li class="mbtrdot">',
		        		'<a href="',author.link,'">',author.name,'</a>: <br/> ',
						content, 
						'<br/><span class="pl">',update,'</span>',
					'</li>'				
				].join(''));
			}
		});
		html = html.join('');
		$('#banliao_list').append(html);
		var board_content = $('#banliao_content');
		board_content.attr('scrollTop',board_content.attr('scrollHeight'));
	};
}

function Sender(id, getterObj, userOptions){
	var topicId = id;
	var getter = getterObj
	var ck = get_cookie('ck');
	var options = {
		textareaid : '#banliao_input',
		urlPre : URLPRE
	};
	jQuery.extend(options, userOptions);
	
	this.send = function(){
		var url = options.urlPre + topicId + '/add_comment';
		var content = $(options.textareaid).val();
		content = $.trim(content);
		if ( ! content){
			return false;
		}
		var tp = getter.getTotalPage();
		if (tp > 1){
			var start = (tp - 1) * 100;
		}
		else{
			start = 0;
		}
		$.post(url, {
			ck : get_cookie('ck'),
			rv_comment : content,
			start : start
		},function(r){
			$(options.textareaid).val('');
			getter.process(r);
		});
	}
	
}

window.Getter  = Getter;	
window.Updater = Updater;
window.Sender  = Sender;
})(jQuery);

